// Copyright Epic Games, Inc. All Rights Reserved.

#include "LyraDamageExecution.h"
#include "AbilitySystem/Attributes/LyraHealthSet.h"
#include "AbilitySystem/Attributes/LyraCombatSet.h"
#include "AbilitySystem/LyraGameplayEffectContext.h"
#include "AbilitySystem/LyraAbilitySourceInterface.h"
#include "Engine/World.h"
#include "LyraLogChannels.h"
#include "Teams/LyraTeamSubsystem.h"

#include UE_INLINE_GENERATED_CPP_BY_NAME(LyraDamageExecution)

// 伤害计算静态数据
struct FDamageStatics
{
	FGameplayEffectAttributeCaptureDefinition BaseDamageDef; // 基础伤害属性捕获定义

	FDamageStatics()
	{
		BaseDamageDef = FGameplayEffectAttributeCaptureDefinition(ULyraCombatSet::GetBaseDamageAttribute(), EGameplayEffectAttributeCaptureSource::Source, true);
	}
};

// 获取伤害静态数据
static FDamageStatics& DamageStatics()
{
	static FDamageStatics Statics;
	return Statics;
}

// 构造函数
ULyraDamageExecution::ULyraDamageExecution()
{
	RelevantAttributesToCapture.Add(DamageStatics().BaseDamageDef); // 添加基础伤害属性到相关捕获属性列表
}

/**
 * 执行伤害计算的具体实现
 */
void ULyraDamageExecution::Execute_Implementation(const FGameplayEffectCustomExecutionParameters& ExecutionParams, FGameplayEffectCustomExecutionOutput& OutExecutionOutput) const
{
#if WITH_SERVER_CODE
	const FGameplayEffectSpec& Spec = ExecutionParams.GetOwningSpec(); // 获取拥有的游戏效果规格
	FLyraGameplayEffectContext* TypedContext = FLyraGameplayEffectContext::ExtractEffectContext(Spec.GetContext()); // 提取类型化的游戏效果上下文
	check(TypedContext); // 检查类型化上下文是否有效

	const FGameplayTagContainer* SourceTags = Spec.CapturedSourceTags.GetAggregatedTags(); // 获取源标签容器
	const FGameplayTagContainer* TargetTags = Spec.CapturedTargetTags.GetAggregatedTags(); // 获取目标标签容器

	FAggregatorEvaluateParameters EvaluateParameters; // 聚合器评估参数
	EvaluateParameters.SourceTags = SourceTags; // 设置源标签
	EvaluateParameters.TargetTags = TargetTags; // 设置目标标签

	float BaseDamage = 0.0f; // 基础伤害值
	ExecutionParams.AttemptCalculateCapturedAttributeMagnitude(DamageStatics().BaseDamageDef, EvaluateParameters, BaseDamage); // 尝试计算捕获属性的大小

	const AActor* EffectCauser = TypedContext->GetEffectCauser(); // 获取效果引发者
	const FHitResult* HitActorResult = TypedContext->GetHitResult(); // 获取命中结果

	AActor* HitActor = nullptr; // 命中的演员
	FVector ImpactLocation = FVector::ZeroVector; // 碰撞位置
	FVector ImpactNormal = FVector::ZeroVector; // 碰撞法线
	FVector StartTrace = FVector::ZeroVector; // 追踪起点
	FVector EndTrace = FVector::ZeroVector; // 追踪终点

	// 计算命中的演员、表面、区域和距离都依赖于计算是否有命中结果
	// 直接添加而没有目标的效果将始终没有命中结果，必须回退到一些备用信息
	if (HitActorResult)
	{
		const FHitResult& CurHitResult = *HitActorResult; // 当前命中结果
		HitActor = CurHitResult.HitObjectHandle.FetchActor(); // 获取命中的演员
		if (HitActor)
		{
			ImpactLocation = CurHitResult.ImpactPoint; // 设置碰撞位置
			ImpactNormal = CurHitResult.ImpactNormal; // 设置碰撞法线
			StartTrace = CurHitResult.TraceStart; // 设置追踪起点
			EndTrace = CurHitResult.TraceEnd; // 设置追踪终点
		}
	}

	// 处理没有命中结果或命中结果没有返回演员的情况
	UAbilitySystemComponent* TargetAbilitySystemComponent = ExecutionParams.GetTargetAbilitySystemComponent(); // 获取目标能力系统组件
	if (!HitActor)
	{
		HitActor = TargetAbilitySystemComponent ? TargetAbilitySystemComponent->GetAvatarActor_Direct() : nullptr; // 获取目标能力系统组件的化身演员
		if (HitActor)
		{
			ImpactLocation = HitActor->GetActorLocation(); // 设置碰撞位置为演员位置
		}
	}

	// 应用团队伤害/自我伤害等规则
	float DamageInteractionAllowedMultiplier = 0.0f; // 伤害交互允许乘数
	if (HitActor)
	{
		ULyraTeamSubsystem* TeamSubsystem = HitActor->GetWorld()->GetSubsystem<ULyraTeamSubsystem>(); // 获取团队子系统
		if (ensure(TeamSubsystem))
		{
			DamageInteractionAllowedMultiplier = TeamSubsystem->CanCauseDamage(EffectCauser, HitActor) ? 1.0 : 0.0; // 检查是否允许造成伤害
		}
	}

	// 确定距离
	double Distance = WORLD_MAX; // 距离

	if (TypedContext->HasOrigin()) // 检查上下文是否有原点
	{
		Distance = FVector::Dist(TypedContext->GetOrigin(), ImpactLocation); // 计算原点到碰撞位置的距离
	}
	else if (EffectCauser) // 检查效果引发者是否存在
	{
		Distance = FVector::Dist(EffectCauser->GetActorLocation(), ImpactLocation); // 计算效果引发者位置到碰撞位置的距离
	}
	else
	{
		UE_LOG(LogLyraAbilitySystem, Error, TEXT("Damage Calculation cannot deduce a source location for damage coming from %s; Falling back to WORLD_MAX dist!"), *GetPathNameSafe(Spec.Def)); // 记录错误日志
	}

	// 应用能力源修饰符
	float PhysicalMaterialAttenuation = 1.0f; // 物理材质衰减
	float DistanceAttenuation = 1.0f; // 距离衰减
	if (const ILyraAbilitySourceInterface* AbilitySource = TypedContext->GetAbilitySource()) // 获取能力源接口
	{
		if (const UPhysicalMaterial* PhysMat = TypedContext->GetPhysicalMaterial()) // 获取物理材质
		{
			PhysicalMaterialAttenuation = AbilitySource->GetPhysicalMaterialAttenuation(PhysMat, SourceTags, TargetTags); // 获取物理材质衰减
		}

		DistanceAttenuation = AbilitySource->GetDistanceAttenuation(Distance, SourceTags, TargetTags); // 获取距离衰减
	}
	DistanceAttenuation = FMath::Max(DistanceAttenuation, 0.0f); // 确保距离衰减不小于0

	// 当伤害转换为负健康值时进行钳制
	const float DamageDone = FMath::Max(BaseDamage * DistanceAttenuation * PhysicalMaterialAttenuation * DamageInteractionAllowedMultiplier, 0.0f); // 计算最终造成的伤害

	if (DamageDone > 0.0f) // 检查伤害是否大于0
	{
		// 应用伤害修饰符，这将在目标上转换为负健康值
		OutExecutionOutput.AddOutputModifier(FGameplayModifierEvaluatedData(ULyraHealthSet::GetDamageAttribute(), EGameplayModOp::Additive, DamageDone)); // 添加输出修饰符
	}
#endif // #if WITH_SERVER_CODE
}